using System;
using System.Collections.Generic;
using System.Linq;

using ChessKit.ChessLogic;

using NUnit.Framework;

namespace UnitTests.Env
{
	public class Synch
	{
		private Board _target;
		private readonly ITestBoard _source;
		private readonly Random _rnd;
		private List<Move> _targetPossibleMoves;
		private List<Move> _sourcePossibleMoves;

		public Synch(Board target, ITestBoard source, Random rnd)
		{
			_target = target;
			_source = source;
			_rnd = rnd;
		}
		public bool ShouldEnd { get { return _target.MoveNumber > 200; } }
		public string CurrentTargetPosition { get { return _target.ToFenString(); } }
		public string CurrentSourcePosition { get { return _source.Fen; } }
		public List<Move> TargetPossibleMoves { get { return _targetPossibleMoves ?? (_targetPossibleMoves = _target.GetLegalMoves()); } }
		public List<Move> SourcePossibleMoves { get { return _sourcePossibleMoves ?? (_sourcePossibleMoves = _source.GetAllLegalMoves().ToList()); } }

		public IEnumerable<Move> GetWronglyValidMoves()
		{
			return TargetPossibleMoves.Except(SourcePossibleMoves);
		}
		public IEnumerable<Move> GetWronglyInvalidMoves()
		{
			return SourcePossibleMoves.Except(TargetPossibleMoves);
		}

		public void MakeRandomMove()
		{
			var original = CurrentTargetPosition;
			var randomMove = SourcePossibleMoves[_rnd.Next(SourcePossibleMoves.Count)];

			var mySan = _target.GetSan(TargetPossibleMoves.Single(m => m == randomMove));
			var sourceSan = _source.GetSan(randomMove);
			if (mySan != sourceSan)
			{
				Console.WriteLine("???;{0};{1};{2}", original, randomMove, sourceSan);
				Assert.Fail();

			}
      var move = default(Move);
		  try
		  {
		    move = _target.ParseMoveFromSan(mySan);
		  }
		  catch (Exception)
		  {
//		    Console.WriteLine(e);
		  }
      if (move != randomMove)
      {
        Console.WriteLine("???;{0};{1};{2}", original, randomMove, sourceSan);
        Assert.Fail();
      }
//      move.ToString().Should().Be(newBoard.PreviousMove.ToString());

			_target = _target.MakeMove(randomMove);
			_source.MakeMove(randomMove);

			//      var fen = _source.Fen;
			//      if (fen != CurrentTargetPosition)
			//      {
			//        Console.WriteLine(
			//           "[TestCase(\"TestFen???\", \"{0}\", \"{1}\", \"{2}\")]",
			//           original, randomMove, fen);
			//        Assert.Fail();
			//      }
			_targetPossibleMoves = null;
			_sourcePossibleMoves = null;
		}
	}
}